package main

import (
	"fmt"
	"math/rand"
)

func hello() {
	fmt.Println("Hello Goroutine!")
}
func main() {
	// go hello() // 启动另外一个goroutine去执行hello函数
	// fmt.Println("main goroutine done!")
	// time.Sleep(time.Second)

	// 合起来写
	// go func() {
	// 	i := 0
	// 	for {
	// 		i++
	// 		fmt.Printf("new goroutine: i = %d\n", i)
	// 		time.Sleep(time.Second)
	// 	}
	// }()
	// i := 0
	// for {
	// 	i++
	// 	fmt.Printf("main goroutine: i = %d\n", i)
	// 	time.Sleep(time.Second)
	// 	if i == 2 {
	// 		break
	// 	}
	// }

	// go func(s string) {
	// 	for i := 0; i < 2; i++ {
	// 		fmt.Println(s)
	// 	}
	// }("world")
	// // 主协程
	// for i := 0; i < 2; i++ {
	// 	// 切一下，再次分配任务
	// 	runtime.Gosched()
	// 	fmt.Println("hello")
	// }

	// go func() {
	// 	defer fmt.Println("A.defer")
	// 	func() {
	// 		defer fmt.Println("B.defer")
	// 		// 结束协程
	// 		runtime.Goexit()
	// 		defer fmt.Println("C.defer")
	// 		fmt.Println("B")
	// 	}()
	// 	fmt.Println("A")
	// }()
	// for {
	// }

	// runtime.GOMAXPROCS(4)
	// go a()
	// go b()
	// go c()
	// go d()
	// time.Sleep(time.Second)

	// var ch chan int
	// fmt.Println(ch) // <nil>

	// ch := make(chan int)
	// ch <- 10 // 把10发送到ch中
	// // x := <-ch // 从ch中接收值并赋值给变量x
	// <-ch // 从ch中接收值，忽略结果

	// fmt.Println(<-ch)
	// close(ch)

	// ch := make(chan int) // 创建一个int类型的通道
	// go func() {
	// 	ch <- 10 // 向通道发送值为10的元素
	// }()
	// fmt.Println("从通道接收到的值为：", <-ch) // 从通道接收并打印值

	// ch := make(chan int)
	// go recv(ch) // 启用goroutine从通道接收值
	// ch <- 10
	// fmt.Println("发送成功")

	// ch := make(chan int, 1) // 创建一个容量为1的有缓冲区通道
	// ch <- 10
	// fmt.Println("接收成功", <-ch)
	// fmt.Println("接收成功", ch)
	// fmt.Println("发送成功")

	// c := make(chan int)
	// go func() {
	// 	for i := 0; i < 5; i++ {
	// 		c <- i
	// 	}
	// 	close(c)
	// }()
	// for {
	// 	if data, ok := <-c; ok {
	// 		fmt.Println(data)
	// 	} else {
	// 		break
	// 	}
	// }
	// fmt.Println("main结束")

	// ch1 := make(chan int)
	// ch2 := make(chan int)
	// // 开启goroutine将0~100的数发送到ch1中
	// go func() {
	// 	for i := 0; i < 100; i++ {
	// 		ch1 <- i
	// 	}
	// 	close(ch1)
	// }()
	// // 开启goroutine从ch1中接收值，并将该值的平方发送到ch2中
	// go func() {
	// 	for {
	// 		i, ok := <-ch1 // 通道关闭后再取值ok=false
	// 		if !ok {
	// 			break
	// 		}
	// 		ch2 <- i * i
	// 	}
	// 	close(ch2)
	// }()
	// // 在主goroutine中从ch2中接收值打印
	// for i := range ch2 { // 通道关闭后会退出for range循环
	// 	fmt.Println(i)
	// }

	// ch1 := make(chan int)
	// ch2 := make(chan int)
	// go counter(ch1)
	// go squarer(ch2, ch1)
	// printer(ch2)

	// 需要2个管道
	// 1.job管道
	jobChan := make(chan *Job, 128)
	// 2.结果管道
	resultChan := make(chan *Result, 128)
	// 3.创建工作池
	createPool(64, jobChan, resultChan)
	// 4.开个打印的协程
	go func(resultChan chan *Result) {
		// 遍历结果管道打印
		for result := range resultChan {
			fmt.Printf("job id:%v randnum:%v result:%d\n", result.job.Id,
				result.job.RandNum, result.sum)
		}
	}(resultChan)
	var id int
	// 循环创建job，输入到管道
	for {
		id++
		// 生成随机数
		r_num := rand.Int()
		job := &Job{
			Id:      id,
			RandNum: r_num,
		}
		jobChan <- job
	}

}

// 创建工作池
// 参数1：开几个协程
func createPool(num int, jobChan chan *Job, resultChan chan *Result) {
	// 根据开协程个数，去跑运行
	for i := 0; i < num; i++ {
		go func(jobChan chan *Job, resultChan chan *Result) {
			// 执行运算
			// 遍历job管道所有数据，进行相加
			for job := range jobChan {
				// 随机数接过来
				r_num := job.RandNum
				// 随机数每一位相加
				// 定义返回值
				var sum int
				for r_num != 0 {
					tmp := r_num % 10
					sum += tmp
					r_num /= 10
				}
				// 想要的结果是Result
				r := &Result{
					job: job,
					sum: sum,
				}
				//运算结果扔到管道
				resultChan <- r
			}
		}(jobChan, resultChan)
	}
}

type Job struct {
	// id
	Id int
	// 需要计算的随机数
	RandNum int
}

type Result struct {
	// 这里必须传对象实例
	job *Job
	// 求和
	sum int
}

func counter(out chan<- int) {
	for i := 0; i < 100; i++ {
		out <- i
	}
	close(out)
}

func squarer(out chan<- int, in <-chan int) {
	for i := range in {
		out <- i * i
	}
	close(out)
}
func printer(in <-chan int) {
	for i := range in {
		fmt.Println(i)
	}
}

func recv(c chan int) {
	ret := <-c
	fmt.Println("接收成功", ret)
}

func a() {
	for i := 1; i < 10; i++ {
		fmt.Println("A:", i)
	}
}

func b() {
	for i := 1; i < 10; i++ {
		fmt.Println("B:", i)
	}
}

func c() {
	for i := 1; i < 10; i++ {
		fmt.Println("C:", i)
	}
}

func d() {
	for i := 1; i < 10; i++ {
		fmt.Println("D:", i)
	}
}
